#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/io.h>
#include <linux/string.h>
#include <linux/platform_device.h>

#include "led_resources.h"
#include "led_operation.h"
#include "led_driver.h"

static int led_pin[100];
static int led_cnt = 0;

static int board_demo_led_init (int which) /* 初始化LED, which-哪个LED */       
{   
    //printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which);
    
    printk(KERN_INFO "init gpio: group %d, pin %d\n", GROUP(led_pin[which]), PIN(led_pin[which]));
    switch(GROUP(led_pin[which]))
    {
        case 0:
        {
            printk(KERN_INFO "init pin of group 0 ...\n");
            break;
        }
        case 1:
        {
            printk(KERN_INFO "init pin of group 1 ...\n");
            break;
        }
        case 2:
        {
            printk(KERN_INFO "init pin of group 2 ...\n");
            break;
        }
        case 3:
        {
            printk(KERN_INFO "init pin of group 3 ...\n");
            break;
        }
    }
    
    return 0;
}

static int board_demo_led_ctl (int which, char status) /* 控制LED, which-哪个LED, status:1-亮,0-灭 */
{
    //printk("%s %s line %d, led %d, %s\n", __FILE__, __FUNCTION__, __LINE__, which, status ? "on" : "off");
    printk(KERN_INFO "set led %s: group %d, pin %d\n", status ? "on" : "off", GROUP(led_pin[which]), PIN(led_pin[which]));

    switch(GROUP(led_pin[which]))
    {
        case 0:
        {
            printk(KERN_INFO "set pin of group 0 ...\n");
            break;
        }
        case 1:
        {
            printk(KERN_INFO "set pin of group 1 ...\n");
            break;
        }
        case 2:
        {
            printk(KERN_INFO "set pin of group 2 ...\n");
            break;
        }
        case 3:
        {
            printk(KERN_INFO "set pin of group 3 ...\n");
            break;
        }
    }

    return 0;
}

static struct led_operations board_demo_led_opr = {
    .init = board_demo_led_init,
    .ctrl  = board_demo_led_ctl,
};

struct led_operations *get_board_led_opr(void)
{
    return &board_demo_led_opr;
}

static int led_drv_probe(struct platform_device *dev){
    int i;
    struct resource *res;
    for(i = 0; i < 100; i++){
        res = platform_get_resource(dev, IORESOURCE_IRQ, i);
        if(!res){
            //printk(KERN_ERR "[%s]:platform_get_resource error\n",__FUNCTION__);
            break;
        }
        led_pin[i] = res->start;
        led_class_create_device(led_cnt);
        led_cnt++;
    }

    return 0;
}

static int led_drv_remove(struct platform_device *dev){
    int i;
    struct resource *res;
    for(i = 0; i < led_cnt; i++){
        res = platform_get_resource(dev, IORESOURCE_IRQ, i);
        if(!res){
            printk(KERN_ERR "[%s]:platform_get_resource error\n",__FUNCTION__);
            break;
        }
        led_class_destroy_device(i);
        led_cnt--;
    }

    return 0;
}

static struct platform_driver imx_led ={
    .probe  = led_drv_probe,
    .remove = led_drv_remove,
    .driver ={
        .name = "fison_led_platform",
    } 
};

static int __init led_drv_init(void){
    int err = platform_driver_register(&imx_led);
    register_led_operations(&board_demo_led_opr);
    return 0;
}

static void __exit led_drv_exit(void){
    platform_driver_unregister(&imx_led);
}

module_init(led_drv_init);
module_exit(led_drv_exit);

MODULE_AUTHOR("fison");
MODULE_DESCRIPTION("led driver for imx6ull");
MODULE_LICENSE("GPL");